home *** CD-ROM | disk | FTP | other *** search
/ Network PC / Network PC.iso / amiga utilities / communication / internet / amitcp3.0b / src.lha / src / amitcp / api / amiga_api.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-08  |  16.7 KB  |  616 lines

  1. RCS_ID_C="$Id: amiga_api.c,v 3.7 1994/04/02 11:12:59 jraja Exp $";
  2. /*
  3.  * Copyright (c) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
  4.  *                    Helsinki University of Technology, Finland.
  5.  *                    All rights reserved.
  6.  *
  7.  * Created: Tue Jan 26 20:44:28 1993 too
  8.  * Last modified: Mon Feb 14 16:48:27 1994 jraja
  9.  *
  10.  * HISTORY
  11.  * $Log: amiga_api.c,v $
  12.  * Revision 3.7  1994/04/02  11:12:59  jraja
  13.  * Added initialization of the resolver variables.
  14.  *
  15.  * Revision 3.6  1994/03/22  07:36:28  jraja
  16.  * Added initialization of the fdCallback to NULL. Also clearing the
  17.  * fdCallback pointer before the final CloseSocket sweep on the library
  18.  * close.
  19.  * Removed f_void definition, already defined in apicalls.h.
  20.  *
  21.  * Revision 3.5  1994/02/14  14:49:20  jraja
  22.  * Changed the default log tag to be NULL (no tag).
  23.  *
  24.  * Revision 3.4  1994/01/20  02:23:44  jraja
  25.  * Changed writeErrnoValue() to use only errno sizes of 1, 2 or 4 bytes.
  26.  *
  27.  * Revision 3.3  1994/01/12  07:17:58  jraja
  28.  * Added initialization of the Syslog() related variables of the library base.
  29.  *
  30.  * Revision 3.2  1994/01/07  15:40:29  too
  31.  * Bug fixes after revision 3.1. Now tested.
  32.  *
  33.  * Revision 3.1  1994/01/04  14:24:05  too
  34.  * Addeed compile time fd_mask and long sizeof checks.
  35.  * Added allocation of socket usage bitmask (at then end of dTable)
  36.  *
  37.  * Revision 1.50  1993/11/26  16:23:42  too
  38.  * Added sendbreaktotasks() function
  39.  *
  40.  * Revision 1.49  1993/08/09  21:28:22  ppessi
  41.  * Added revision headers and release string.
  42.  *
  43.  * Revision 1.48  1993/08/06  08:42:44  jraja
  44.  * Removed the version check, since it does not work.
  45.  *
  46.  * Revision 1.47  1993/08/05  10:35:52  jraja
  47.  * Added version check to the ELL_Open(). Now all Open requests with
  48.  * version less than 2 will be rejected.
  49.  * No requester or alert is set up yet (Add later).
  50.  *
  51.  * Revision 1.46  1993/07/15  20:17:25  too
  52.  * Changed library revision to VERSION 2 REVISION 1
  53.  *
  54.  * Revision 1.45  1993/06/12  22:56:08  too
  55.  * Added freeDataBuffer() calls to UL_Close so now selitem and netdb
  56.  * buffers are freed at CloseLIbrary()
  57.  *
  58.  * Revision 1.44  1993/06/07  12:37:20  too
  59.  * Changed inet_ntoa, netdatabase functions and WaitSelect() use
  60.  * separate buffers for their dynamic buffers
  61.  *
  62.  */
  63.  
  64. #include <bsdsocket.library_rev.h>
  65. #define RELEASESTRING "AmiTCP/IP release 3 "
  66.  
  67. /*
  68.  * NOTE: Exec has turned off task switching while in Open, Close, Expunge and
  69.  *     Reserved functions (via Forbid()/Permit()) so we should not take
  70.  *     too long in them.
  71.  */
  72.  
  73. #include <conf.h>
  74.  
  75. #include <sys/param.h>
  76. #include <sys/systm.h>
  77. #include <sys/syslog.h>
  78.  
  79. #include <kern/amiga_includes.h>
  80.  
  81. #include <api/amiga_api.h>
  82. #include <api/allocdatabuffer.h>
  83. #include <api/amiga_libcallentry.h>
  84. #include <api/apicalls.h>
  85.  
  86. #include <kern/amiga_subr.h>
  87. #include <kern/amiga_log.h>
  88.  
  89. #if sizeof (fd_mask) != 4 || sizeof (long) != 4
  90. #error AmiTCP/IP currently depends on fd_mask and longword size of 32 bits.
  91. #endif
  92.  
  93. #define SOCLIBNAME "bsdsocket.library\0\0" /* space for ".n" at the end */
  94.  
  95. /*
  96.  *  Semaphore to prevent simultaneous access to library functions.
  97.  */
  98. struct SignalSemaphore syscall_semaphore = { 0 };
  99.  
  100. /*
  101.  *  some globals.
  102.  */
  103. struct Library *MasterSocketBase = NULL;
  104. struct List    socketBaseList;         /* list of opened socket library bases */
  105. struct List    garbageSocketBaseList; /* list of libray bases not active
  106.                       anymore (NOT YET IMPLEMENTED) */
  107. struct List    releasedSocketList; /* List for sockets that are in no-one's
  108.                        context, waiting for Obtain */
  109.  
  110. extern struct Task * AmiTCP_Task; /* reference to AmiTCP/IP task information */
  111.  
  112. /*
  113.  * Declaration of variable to hold message format string when one
  114.  * task tries to use other tasks' library base pointer. moved here
  115.  * from amiga_libcallentry.h so it doens't generate code.
  116.  */
  117. const char wrongTaskErrorFmt[] =
  118.   "Task %ld (%s) attempted to use library base of Task %ld (%s).";
  119.  
  120. /*
  121.  * Instead of using exec/initializers.h we looked it as a reference
  122.  * and wrote InitTable by hand
  123.  */
  124.  
  125. /*
  126.  * OFFSET needed to be casted LONG so compiler doesn't give warning
  127.  * about casting pointer to UWORD
  128.  */
  129. #define OFFSET(structName, structEntry) \
  130.   ((LONG)(&(((struct structName *) 0)->structEntry)))
  131.  
  132. /*
  133.  * original initTable of only UWORD items doesn't work, since compiler
  134.  * doesn't know address of SOCNAME and VSTRING at compile time, and
  135.  * those are broken to 2 WORDS. therefore initTable is a structure
  136.  * constructed by hand, and those (LONG) values are set longword aligned.
  137.  */
  138. #define id_byte 0xe000
  139. #define id_word 0xd000
  140. #define id_long 0xc000
  141.  
  142. struct {
  143.   UWORD byte1; UWORD offset1; UWORD ln_type;
  144.   UWORD byte2; UWORD offset2; UWORD lib_flags;
  145.   UWORD long3; UWORD offset3; ULONG ln_Name;
  146.   UWORD word4; UWORD offset4; UWORD lib_Version;
  147.   UWORD word5; UWORD offset5; UWORD lib_Revision;
  148.   UWORD long6; UWORD offset6; ULONG lib_IdString;
  149.   UWORD end7; 
  150.   } Library_initTable = {
  151.     id_byte, OFFSET(Node, ln_Type), NT_LIBRARY << 8,
  152.     id_byte, OFFSET(Library, lib_Flags), (LIBF_SUMUSED|LIBF_CHANGED) << 8,
  153.     id_long, OFFSET(Node, ln_Name), (ULONG)SOCLIBNAME,
  154.     id_word, OFFSET(Library, lib_Version), VERSION,
  155.     id_word, OFFSET(Library, lib_Revision), REVISION,
  156.     id_long, OFFSET(Library, lib_IdString), (ULONG)RELEASESTRING VSTRING,
  157.     0x0000
  158.     };
  159. #undef id_byte
  160. #undef id_word
  161. #undef id_long
  162.  
  163. /*
  164.  * Api show and hide functions.. during these calls system is not
  165.  * inside FOrbid()/Permit() pair
  166.  */
  167.  
  168. enum {    API_SCRATCH,        /* api not initialized */
  169.     API_INITIALIZED,    /* librarybase created */
  170.     API_SHOWN,        /* librarybase made visible */
  171.     API_HIDDEN,        /* librarybase hidden */
  172.     API_FUNCTIONPATCHED    /* Api functions set to return -1 */
  173. } api_state = API_SCRATCH;
  174.  
  175.   /*
  176.    * Setting the following variable to FALSE just before making
  177.    * new socket Library base prevents ELL_Expunge, the final
  178.    * expunging function to remove library base from memory
  179.    */
  180. BOOL AmiTCP_lets_you_do_expunge = FALSE;
  181.  
  182. BOOL SB_Expunged = FALSE; /* boolean value set by ELL_Expunge */
  183.  
  184.  
  185. struct Library * SAVEDS RAF2(ELL_Open,
  186.                  struct Library *,    libPtr,        a6,
  187.                  ULONG,        version,    d0)
  188. #if 0
  189. {
  190. #endif
  191.   
  192.   extern f_void UserLibrary_funcTable[];
  193.   struct SocketBase * newBase;
  194.   LONG error;
  195.   WORD * i;
  196.  
  197.   /*
  198.    * One task may open socket library more than once. In that case caller
  199.    * receives the base it has opened already.
  200.    */
  201.   if ((newBase = FindSocketBase(SysBase->ThisTask)) != NULL) {
  202.     newBase->libNode.lib_OpenCnt++;
  203.     return (struct Library *)newBase;
  204.   }
  205.   /*
  206.    * Create new library base.
  207.    * All fields in the base will first be initialized to zero and then
  208.    * modified by initializers in initTable.
  209.    */
  210.   newBase = (struct SocketBase *)MakeLibrary(UserLibrary_funcTable,
  211.                          (UWORD *)&Library_initTable,
  212.                          NULL,
  213.                          sizeof(struct SocketBase),
  214.                          NULL);
  215.   if (newBase == NULL)
  216.     return NULL;
  217.  
  218.   /*
  219.    * add this newly allocated library base to our list of opened
  220.    * socket libraries
  221.    */    
  222.   AddTail(&socketBaseList, (struct Node *)newBase); 
  223.  
  224.   /*
  225.    * Modify some MASTER library base fields
  226.    */
  227.   libPtr->lib_OpenCnt++;        /* mark us as having another opener */
  228.   libPtr->lib_Flags&= ~LIBF_DELEXP;    /* prevent delayed expunges */
  229.  
  230.   /*
  231.    * Initialize new library base
  232.    */
  233.   for (i = (WORD *)((struct Library *)newBase + 1);
  234.        i < (WORD *)(newBase + 1);
  235.        i++)
  236.     *i = 0L;
  237.   newBase->libNode.lib_OpenCnt = 1;
  238.   newBase->errnoPtr = (VOID *)&newBase->defErrno;
  239.   newBase->errnoSize = sizeof newBase->defErrno;
  240.   newBase->thisTask = SysBase->ThisTask;
  241.   newBase->sigIntrMask = SIGBREAKF_CTRL_C;
  242.   
  243.   /* initialize syslog variables */
  244. #if 0 /* initialization to zero is implicit */
  245.   newBase->LogTag = NULL; /* no tag by default, old apps print a tag already */
  246. #endif
  247.   newBase->LogFacility = LOG_USER;
  248.   newBase->LogMask = 0xff;
  249.  
  250.   /* initialize resolver variables */
  251.   newBase->hErrnoPtr = &newBase->defHErrno;
  252.   newBase->res_socket = -1;
  253.   res_init(&newBase->res_state);
  254.  
  255.   /* initialize dtable variables */
  256. #if 0 /* initialization to zero is implicit */
  257.   newBase->fdCallback = NULL;
  258. #endif
  259.   newBase->dTableSize = FD_SETSIZE;
  260.   if ((newBase->dTable =
  261.        AllocMem(newBase->dTableSize * sizeof (struct socket *) +
  262.         ((newBase->dTableSize - 1) / NFDBITS + 1) * sizeof (fd_mask),
  263.         MEMF_CLEAR|MEMF_PUBLIC)) != NULL) {
  264.     /*    
  265.      * allocate and initialize the timer message reply port
  266.      */
  267.     newBase->timerPort = CreateMsgPort();
  268.     if (newBase->timerPort != NULL) {
  269.       /*
  270.        * Disable signalling for now
  271.        */
  272.       newBase->timerPort->mp_Flags = PA_IGNORE;
  273.       /*
  274.        * allocate and initialize the timerequest
  275.        */
  276.       newBase->tsleep_timer = (struct timerequest *)
  277.     CreateIORequest(newBase->timerPort, sizeof(struct timerequest));
  278.       if (newBase->tsleep_timer != NULL) {
  279.     error = OpenDevice(TIMERNAME, UNIT_VBLANK, 
  280.                (struct IORequest *)newBase->tsleep_timer, 0);
  281.     if (error == 0) {
  282.       /*
  283.        * Initialize some fields of the IO request to common values
  284.        */
  285.       newBase->tsleep_timer->tr_node.io_Command = TR_ADDREQUEST;
  286.       newBase->tsleep_timer->tr_node.io_Message.mn_Node.ln_Type = NT_UNKNOWN;
  287.       return (struct Library *)newBase;
  288.     }
  289.       }
  290.     }
  291.   }
  292.   /*
  293.    * There was some error if we reached here. Call Close to clean up.
  294.    */
  295.   {
  296. #if __GNUC__
  297.     extern ULONG* REGARGFUN UL_Close(VOID);
  298.     register struct SocketBase *a6 __asm("a6") = newBase;
  299.     UL_Close();
  300. #elif __SASC
  301.     extern ULONG* REGARGFUN UL_Close(register __a6 struct SocketBase *);
  302.     UL_Close(newBase);
  303. #else 
  304. #error Compiler not supported!
  305. #endif
  306.   }
  307.   return NULL;
  308. }
  309.  
  310.  
  311. ULONG * SAVEDS RAF1(ELL_Expunge,
  312.             struct Library *,    libPtr, a6)
  313. #if 0
  314. {
  315. #endif
  316.   /*
  317.    * Since every user gets her own library base, Major library base
  318.    * can be removed immediately after 
  319.    */ 
  320.   if (libPtr->lib_OpenCnt == 0 && AmiTCP_lets_you_do_expunge) {
  321.     VOID * freestart;
  322.     ULONG  size;
  323.  
  324. #if 0    /* Currently done already  */
  325.     /*
  326.      * unlink SocketBase from System Library list
  327.      */
  328.     Remove((struct Node *)libPtr);
  329. #endif
  330.     
  331.     freestart = (void *)((ULONG)libPtr - (ULONG)libPtr->lib_NegSize);
  332.     size = libPtr->lib_NegSize + libPtr->lib_PosSize;
  333.     FreeMem(freestart, size);
  334.     MasterSocketBase = NULL; 
  335.  
  336.     SB_Expunged = TRUE;
  337.     Signal(AmiTCP_Task, SIGBREAKF_CTRL_F);
  338.     return NULL; /* no AmigaDos seglist there (for system use) */
  339.   }
  340.   /*
  341.    * here if someone still have us open, or AmiTCP don't let us expunge yet
  342.    */
  343.   libPtr->lib_Flags |= LIBF_DELEXP;    /* set delayed expunge flag */
  344.   SB_Expunged = FALSE;
  345.   return NULL;
  346. }
  347.  
  348. LONG /* SAVEDS */ Null(void)
  349. {
  350.   return 0L;
  351. }
  352.  
  353. LONG /* SAVEDS */ Garbage(void)
  354. {     
  355.   return -1L;
  356. }
  357.  
  358.  
  359. ULONG * SAVEDS RAF1(UL_Close,
  360.       struct SocketBase *,    libPtr, a6)
  361. #if 0
  362. {
  363. #endif
  364.   
  365.   VOID * freestart;
  366.   ULONG  size;
  367.   int     i;
  368.  
  369.   /*
  370.    * one task may have SocketLibrary opened more than once.
  371.    */
  372.   if (--libPtr->libNode.lib_OpenCnt > 0)
  373.     return NULL;
  374. #ifdef DEBUG
  375.   log(LOG_DEBUG, "Closing proc 0x%lx base 0x%lx\n", 
  376.       libPtr->thisTask, libPtr);
  377. #endif
  378.   /*
  379.    * Since library base is to be closed, all sockets referenced by this
  380.    * library base must be closed too. Next piece of code searches for open
  381.    * sockets and calls CloseSocket() on our own library base. It is safe
  382.    * to call since Forbid() state is broken if semaphore needs to be waited.
  383.    *
  384.    * Note that the close may linger. In such case the linger time will be
  385.    * waited. The linger may be interrupted by any signal in sigIntrMask.
  386.    */
  387.   libPtr->fdCallback = NULL; /* don't call the callback any more */
  388.   for (i = 0; i < libPtr->dTableSize; i++)
  389.     if (libPtr->dTable[i] != NULL)
  390.       CloseSocket(libPtr, i);
  391.   
  392.   Remove((struct Node *)libPtr); /* remove this librarybase from our list
  393.                     of opened library bases */
  394.  
  395.   if (libPtr->tsleep_timer) {
  396.     if (libPtr->tsleep_timer->tr_node.io_Device != NULL) {
  397.       AbortIO((struct IORequest *)(libPtr->tsleep_timer));
  398.       CloseDevice((struct IORequest *)libPtr->tsleep_timer);
  399.     }
  400.     DeleteIORequest((struct IORequest *)libPtr->tsleep_timer);
  401.   }
  402.   if (libPtr->timerPort)
  403.     DeleteMsgPort(libPtr->timerPort);
  404.  
  405.   freeDataBuffer(&libPtr->selitems);
  406.   freeDataBuffer(&libPtr->hostents);
  407.   freeDataBuffer(&libPtr->netents);
  408.   freeDataBuffer(&libPtr->protoents);
  409.   freeDataBuffer(&libPtr->servents);
  410.   
  411.   if (libPtr->dTable) 
  412.     FreeMem(libPtr->dTable, libPtr->dTableSize * sizeof (struct socket *) +
  413.         ((libPtr->dTableSize - 1) / NFDBITS + 1) * sizeof (fd_mask));
  414.  
  415.   freestart = (void *)((ULONG)libPtr - (ULONG)libPtr->libNode.lib_NegSize);
  416.   size = libPtr->libNode.lib_NegSize + libPtr->libNode.lib_PosSize;
  417.   bzero(freestart, size);
  418.   FreeMem(freestart, size);
  419.  
  420.   MasterSocketBase->lib_OpenCnt--;
  421.   /*
  422.    * If no more libraries are open and delayed expunge is asked,
  423.    * ELL_expunge() is called.
  424.    */
  425.   if (MasterSocketBase->lib_OpenCnt == 0 &&
  426.       (MasterSocketBase->lib_Flags & LIBF_DELEXP)) {
  427. #if __GNUC__
  428.     register struct Library *a6 __asm("a6") = MasterSocketBase;
  429.     return ELL_Expunge();
  430. #elif __SASC
  431.     return ELL_Expunge(MasterSocketBase);
  432. #else 
  433. #error Compiler not supported!
  434. #endif
  435.   }
  436.  
  437.   return NULL; /* allways return null */
  438. }
  439.  
  440. BOOL api_init()
  441. {
  442.   extern void select_init(void);
  443.   extern f_void ExecLibraryList_funcTable[];
  444.   
  445.   if (api_state != API_SCRATCH)
  446.     return TRUE;
  447.  
  448.   AmiTCP_lets_you_do_expunge = FALSE;
  449.   
  450.   MasterSocketBase = MakeLibrary(ExecLibraryList_funcTable,
  451.                  (UWORD *)&Library_initTable,
  452.                  NULL,
  453.                  sizeof(struct Library),
  454.                  NULL);
  455.   if (MasterSocketBase == NULL)
  456.     return FALSE;
  457.  
  458.   InitSemaphore(&syscall_semaphore);
  459.   select_init(); /* initializes data Select() needs */
  460.   NewList(&socketBaseList);
  461.   NewList(&garbageSocketBaseList);
  462.   NewList(&releasedSocketList);
  463.  
  464.   api_state = API_INITIALIZED;
  465.   return TRUE;
  466. }
  467.  
  468. LONG nthLibrary = 0;
  469.  
  470. BOOL api_show()
  471. {
  472.   struct Node * libNode;
  473.   STRPTR libName = (STRPTR)Library_initTable.ln_Name;
  474.  
  475.   if (api_state == API_SHOWN)
  476.     return TRUE;
  477.   if (api_state == API_SCRATCH)
  478.     return FALSE;
  479.  
  480.   Forbid();
  481.   for (libNode = SysBase->LibList.lh_Head; libNode->ln_Succ;
  482.        libNode = libNode->ln_Succ) {
  483.     if (!strncmp(libNode->ln_Name, libName, sizeof (SOCLIBNAME) - 3)) {
  484. #ifdef DEBUG
  485.       int i;
  486.       if (libNode->ln_Name[sizeof (SOCLIBNAME) - 3] == '\0') 
  487.     i = 1;
  488.       else 
  489.     i = (BYTE)(libNode->ln_Name[sizeof (SOCLIBNAME) - 2] - '0' + 1);
  490.       if (nthLibrary < i)
  491.     nthLibrary = i;
  492. #else
  493.       Permit();
  494.       return FALSE;
  495. #endif
  496.     }
  497.   }
  498.   Permit();
  499. #ifdef DEBUG
  500.   if (nthLibrary > 8)
  501.     return FALSE;
  502.   if (nthLibrary) {
  503.     libName[sizeof (SOCLIBNAME) - 3] = '.'; 
  504.     libName[sizeof (SOCLIBNAME) - 2] = '0' + nthLibrary;
  505.     libName[sizeof (SOCLIBNAME) - 1] = '\0';
  506.     MasterSocketBase->lib_Node.ln_Name = libName;
  507.   }
  508. #endif
  509.   AddLibrary(MasterSocketBase);
  510.   api_state = API_SHOWN;
  511.   
  512.   return TRUE;
  513. }
  514.  
  515. VOID api_hide()
  516. {
  517.   if (api_state != API_SHOWN)
  518.     return;
  519.   Forbid();
  520.   /* unlink Master SocketBase from System Library list */
  521.   Remove((struct Node*)MasterSocketBase);    
  522.   Permit();
  523.   api_state = API_HIDDEN;
  524. }
  525.  
  526. VOID api_setfunctions() /* DOES NOTHING NOW */
  527. {
  528. /*  struct Node *node2move; */
  529.   
  530.   if (api_state == API_SCRATCH)
  531.     return;
  532.   Forbid();
  533.   if (api_state == API_SHOWN)
  534.     /* unlink Master SocketBase from System Library list */
  535.     Remove((struct Node*)MasterSocketBase);    
  536.  
  537.   /* here SetFunction()s to patch libray calls (forbid()/permit()) */
  538.   /*  while(node2move = RemHead(&socketBaseList))
  539.       AddTail(&garbageSocketBaseList, node2move); */
  540.   Permit();
  541.   api_state = API_FUNCTIONPATCHED;
  542. }
  543.  
  544. /*
  545.  * Send CTRL_C to all tasks having socketbase open. 
  546.  */
  547. VOID api_sendbreaktotasks()
  548. {
  549.   extern struct List socketBaseList; /* :/ */
  550.   struct Node * libNode;
  551.  
  552.   Forbid();
  553.   for (libNode = socketBaseList.lh_Head; libNode->ln_Succ;
  554.        libNode = libNode->ln_Succ)
  555.     if (((struct SocketBase *)libNode)->thisTask != Nettrace_Task)
  556.       Signal(((struct SocketBase *)libNode)->thisTask, SIGBREAKF_CTRL_C);
  557.  
  558.   Permit();
  559. }
  560.  
  561.  
  562. VOID api_deinit()
  563. {
  564. #if DIAGNOSTIC
  565.   if (FindTask(NULL) != AmiTCP_Task)
  566.     log(LOG_ERR, "The calling task of api_deinit() was not AmiTCP/IP");
  567. #endif  
  568.   if (api_state == API_SHOWN || api_state == API_HIDDEN)
  569.     api_setfunctions();
  570.   if (api_state == API_SCRATCH)
  571.     return;
  572.   
  573.   Forbid();
  574.   AmiTCP_lets_you_do_expunge = TRUE;
  575.   {
  576. #if __GNUC__
  577.     register struct Library *a6 __asm("a6") = MasterSocketBase;
  578.     ELL_Expunge();
  579. #elif __SASC
  580.     ELL_Expunge(MasterSocketBase);
  581. #else 
  582. #error Compiler not supported!
  583. #endif
  584.   }
  585.   Permit();
  586.  
  587.   /*
  588.    * if SB_Expunged == FALSE, waiting until last UL_Close() expunges
  589.    * our library.
  590.    */
  591.   while(SB_Expunged == FALSE)
  592.     Wait(SIGBREAKF_CTRL_F);
  593.  
  594.   api_state = API_SCRATCH;
  595. }
  596.  
  597. void writeErrnoValue(struct SocketBase * libPtr, int errno)
  598. {
  599.   /*
  600.    * errnoSize is now restricted to 1, 2 or 4
  601.    */
  602.   BYTE erri = libPtr->errnoSize;
  603.  
  604.   if (erri == 4) {
  605.     *(ULONG *)libPtr->errnoPtr = (ULONG)errno;
  606.     return;
  607.   }
  608.   if (erri == 2) {
  609.     *(UWORD *)libPtr->errnoPtr = (UWORD)errno;
  610.     return;
  611.   }
  612.   /* size must be 1 */
  613.   *(UBYTE *)libPtr->errnoPtr = (UBYTE)errno;
  614.   return;
  615. }
  616.